(does genre have an impact run model on before or after adding genre
compare before and after on the same data) considerations and
limitations - geared towards younger people
Hypothesis Tests on Audio Features
Two sample - independent tests
Independent here means that there is no reason to believe that
observations in the two samples can be paired in any way. (i.e. there’s
no reason to believe the danceability in the 60s is the same as the
2010s)
By randomly shuffling (i.e. permuting) the decade labels we lose any
relationship that there was between decade and danceability. Think of
this shuffling as detaching the labels from rows and then randomly
assigning them back to rows. Then we see which of the following
occurs:
If there was no relationship in the first place (i.e. they are in
fact independent) then randomly shuffling them should have no
implication. If the difference between groups in our sample is much
larger than the difference once the labels are shuffled it’s because
there is a real difference between the groups, and it’s not just down to
sampling variation.
This is an example of the hypothesis tests which were carried out on
each audio feature.
H0: The mean danceability in 1960s is the same as the mean
danceability in 2010s
Ha: The mean danceability in 1960s is less than the mean danceability
in 2010s
H0: The difference in means in 0 Ha: danceability2020 -
danceability1960 > 0
How do the audio features change over time
spotify_data_clean_pivot <- spotify_data_clean_join %>%
pivot_longer(cols = acousticness:valence,
names_to = "audio_feature",
values_to = "value") %>%
group_by(year, audio_feature) %>%
mutate(avg_feature = mean(value))
Plot with all Audio Features
audiot_features_all <- spotify_data_clean_pivot %>%
ggplot() +
aes(x = year, y = avg_feature, group = audio_feature,
colour = audio_feature) +
geom_line(linewidth = 2) +
ylim(0, 100) +
labs(x = "Year",
y = "Value",
title = "Audio Features Over Time",
subtitle = "Avg per year",
colour = "Audio Feature") +
theme_bw() +
scale_colour_brewer(palette = "Dark2") +
theme(axis.text = element_text(face = "bold", size = 15, family = "Times"),
axis.title = element_text(face = "bold", size = 15, family = "Times"),
title = element_text(face = "bold", size = 15, family = "Times"),
legend.text = element_text(face = "bold", size = 10, family = "Times")
)
#ggsave(audiot_features_all, "plot_images/audio_features_all.png")
Plot with audio features showing change
audio_features_cut <- spotify_data_clean_pivot %>%
filter(audio_feature == "acousticness" |
audio_feature == "instrumentalness" |
audio_feature == "danceability" |
audio_feature == "speechiness" |
audio_feature == "loudness") %>%
ggplot() +
aes(x = year, y = avg_feature, group = audio_feature,
colour = audio_feature) +
geom_line(linewidth = 2) +
ylim(0, 100) +
labs(x = "Year",
y = "Value",
title = "Audio Features by Release Year",
subtitle = "Avg per year",
colour = "Audio Feature") +
theme_bw() +
scale_colour_brewer(palette = "Dark2") +
theme(axis.text = element_text(face = "bold", size = 18, family = "Times"),
axis.title = element_text(face = "bold", size = 18, family = "Times"),
title = element_text(face = "bold", size = 18, family = "Times"),
legend.text = element_text(face = "bold", size = 14, family = "Times")
)
ggsave("plot_images/audio_features_cut.png", dpi = 720, width = 12, height = 6)
?ggsave
spotify_data_clean_join %>%
#mutate(explicit = as.numeric(explicit)) %>%
group_by(year) %>%
summarise(total_ex = sum(explicit)) %>%
ggplot() +
aes(x = year, y = total_ex / 20) +
geom_line(colour = "red", linewidth = 2) +
ylim(0, 50) +
labs(x = "Year",
y = "Proportion",
title = "Proportion of Explicit Songs",
subtitle = "by year") +
theme_bw() +
theme(axis.text = element_text(face = "bold", size = 18, family = "Times"),
axis.title = element_text(face = "bold", size = 18, family = "Times"),
title = element_text(face = "bold", size = 18, family = "Times"),
legend.text = element_text(face = "bold", size = 14, family = "Times")
)
ggsave("plot_images/explicit.png", dpi = 720, width = 10, height = 6)

spot_sample %>%
ggplot() +
aes(x = danceability, y = popularity, colour = explicit) +
geom_point() +
geom_smooth(method = "lm")

spot_sample %>%
ggplot() +
aes(x = danceability, y = popularity) +
geom_point(colour = "#1DB954", alpha = 0.8) +
geom_smooth(method = "lm", se = FALSE, colour = "purple3", linewidth = 2) +
labs(x = "Danceability",
y = "Popularity") +
theme_classic() +
theme(axis.text = element_text(face = "bold", size = 18, family = "Times"),
axis.title = element_text(face = "bold", size = 20, family = "Times"),
title = element_text(face = "bold", size = 18, family = "Times"),
legend.text = element_text(face = "bold", size = 14, family = "Times")
)

#ggsave("plot_images/pop_vs_dance.png", dpi = 720, width = 10, height = 6)
spot_sample %>%
ggplot() +
aes(x = loudness, y = popularity) +
geom_point(colour = "#1DB954", alpha = 0.6) +
geom_smooth(method = "lm", se = FALSE, colour = "purple3", linewidth = 2) +
labs(x = "Loudness",
y = "Popularity") +
theme_classic() +
theme(axis.text = element_text(face = "bold", size = 18, family = "Times"),
axis.title = element_text(face = "bold", size = 22, family = "Times"),
title = element_text(face = "bold", size = 18, family = "Times"),
legend.text = element_text(face = "bold", size = 14, family = "Times")
)
ggsave("plot_images/pop_vs_loud.png", dpi = 720, width = 10, height = 6)

Intro To Linear Regression
To help me answer my question of what makes a song “popular” on
spotify, I decided to build an explanatory linear regression model.
This type of analysis is used to determine the strength of the
relationship between a response variable and multiple explanatory
variables.
So in this case I will be choosing from all of the variables I have
just discussed to explain the popularity of a song on spotify.
y = b0 + b1x1 + b2x2 + b3x3….bnxn
popularity = b0 + b1x1 + b2x2 + b3x3….bnxn
To start this process I plot popularity against each one of my
variables or possible explanatory variables and find the strongest
correlation.
n_data <- nrow(spotify_data_for_modelling)
sample_index <- sample(1:n_data, size = n_data*0.1)
spot_sample <- slice(spotify_data_for_modelling, sample_index)
spot_sample %>%
ggplot() +
aes(x = year, y = popularity) +
geom_point(alpha = 0.7, colour = "#1DB954") +
geom_smooth(method = "lm", se = FALSE, colour = "purple2") +
theme_classic() +
labs(x = "Year",
y = "Popularity") +
theme(axis.text = element_text(face = "bold", size = 18, family = "Times"),
axis.title = element_text(face = "bold", size = 18, family = "Times"),
title = element_text(face = "bold", size = 18, family = "Times"),
legend.text = element_text(face = "bold", size = 14, family = "Times")
)

#ggsave("plot_images/pop_vs_dance.png", dpi = 720, width = 10, height = 6)
spot_sample %>%
ggplot() +
aes(x = explicit, y = popularity) +
geom_point(alpha = 0.7, colour = "red4") +
geom_smooth(method = "lm", se = FALSE)

My strongest correlation was year (the year the track was released)
with a correlation of 0.74. I then add this to my model as my first
explanatory variable.
model_1a <- lm(popularity ~ year,
data = train_lm)
summary(model_1a)
Call:
lm(formula = popularity ~ year, data = train_lm)
Residuals:
Min 1Q Median 3Q Max
-19.600 -7.447 -1.773 5.668 54.400
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1220.936768 3.742482 -326.2 <0.0000000000000002 ***
year 0.634644 0.001881 337.4 <0.0000000000000002 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 10.08 on 95918 degrees of freedom
Multiple R-squared: 0.5427, Adjusted R-squared: 0.5427
F-statistic: 1.138e+05 on 1 and 95918 DF, p-value: < 0.00000000000000022
After running my model I’m looking at 3 factors: - The P-value - is
this variable making a significant difference. If the P-value is below
the significance level of 0.05 then we can reject the null hypothesis
and conclude that changes in the
- The R^2 - is a measure that indicates how much of the variation of
popularity is explained by the year
- The adjusted R^2 - compensates for the addition of variables. So as
we’re building an explanatory model, we don’t want this to drop much
lower than the r^2.
model_3a <- lm(popularity ~ year + danceability + loudness,
data = train_lm)
summary(model_3a)
model_3b <- lm(popularity ~ year + danceability + instrumentalness,
data = train_lm)
summary(model_3b)
anova(model_3a, model_2c)
Final Model
So here we have our final model. I stopped adding variables as the
Adjusted r^2 started dropping and our multiple r^2 was barely going
up.
So we can see that the more recent the release, the more
danceability, the louder it is, the less liveness it has. So you don’t
want a live recording, you want a studio recording with some explicit
lyrics chucked in there as well.
All of our P-Values are significant and we have a Multiple r^2 of
0.55, with an adjusted r^2 also of 0.55. This means that 55% of the
variance in popularity is explained our other variables. Which also
means that 45% of the variability in the data cannot be explained by
this model.
55% isn’t a very high proportion but it’s not terrible. We are trying
to measure the popularity of a song. It’s not quite as obvious as if we
were trying to explain the value of a house. We might find that the
postcode and the number of rooms goes a long way to explaining that
value. I think explaining the popularity of a song is bit more
complicated than that. If it was easy to know what made a song popular
then we’d all be musicians.
Mention human behaviour, mention the basic practice of statistics
would call this a moderate effect size.
So my model isn’t great. What can I do to improve this? Well…
When I was researching how spotify calculate their popularity score I
kept coming across this one phrase.
50 is the magic number
The higher your popularity index, the more likely the algorithm is to
recommend you to new listeners, and place you in algorithmic playlists
like Release Radar and Discover Weekly. Many websites and blogs had
theories on what number you had to hit to be added to certain editorial
playlists.
DIYMusician suggests that and popularity of 20+ in the first few
weeks of release will get you onto the Release Radar playlist and a
popularity score of 30+ will get you onto Discover Weekly. Loudlab
suggested that 50 is the magic number. I liked this idea of having a
threshold of whether or not a song is popular. So going back to my
variables I created a column called is_popular which is only TRUE if the
popularity of the song is 50 or over. This also lends itself nicely to a
logistic regression model.
Logistic regression is a statistical analysis method to predict, or
explain a binary outcome, such as yes or no, based on prior observations
of a data set.
So rather than using the popularity score I have used the variable I
created called is_popular, which splits the data in to a logical type,
so it’s TRUE if the song is 50 or above.
The way this is build is very similar to the linear model. I look for
correlations, and I add them to my model 1 at a time. The main
difference is that I’m looking for for a high AUC score this time,
rather than the multiple r^squared I was looking for in the linear
model.
I’ll explain the AUC in a second. I decided for this model to make a
couple of changes. I decided to no longer include the year or decade the
song was released. If I’m staying true to my original question then how
could I possibly write a song that was released in the past. It had such
a large influence on the linear model I thought it would be more
interesting to see how the logistic model fared without it. And then I
can test my model against different decades to see how it performs.
Oscar Wilde is famously credited with having written: “Popularity is
the one insult I have never suffered.”
spot_sample %>%
mutate(explicit = as.logical(explicit)) %>%
ggplot() +
aes(x = loudness, y = popularity, colour = explicit) +
geom_point(alpha = 0.8) +
geom_smooth(method = "lm", se = FALSE) +
labs(x = "Loudness",
y = "Popularity",
title = "Relationship between Popularity and Loundess",
subtitle = "Grouped by explicit or not") +
scale_colour_brewer(palette = "Dark2") +
theme_bw() +
theme(axis.text = element_text(face = "bold", size = 15, family = "Times"),
axis.title = element_text(face = "bold", size = 15, family = "Times"),
title = element_text(face = "bold", size = 15, family = "Times"),
legend.text = element_text(face = "bold", size = 10, family = "Times")
)

spot_sample %>%
mutate(explicit = as.logical(explicit)) %>%
ggplot() +
aes(x = loudness, y = as.integer(is_popular), colour = explicit) +
geom_jitter(shape = 1,
position = position_jitter(h = 0.05, w = 0.05),
alpha = 0.8) +
geom_line(data = train_model_1_loud, aes(x = loudness , y = pred), col = 'red') +
ylab("Probability") +
scale_colour_brewer(palette = "Dark2") +
theme_bw() +
theme(axis.text = element_text(face = "bold", size = 15, family = "Times"),
axis.title = element_text(face = "bold", size = 15, family = "Times"),
title = element_text(face = "bold", size = 15, family = "Times"),
legend.text = element_text(face = "bold", size = 10, family = "Times")
)

# ggplot(mortgage_data) +
# geom_jitter(aes(x = tu_score, y = as.integer(accepted)), shape = 1,
# position = position_jitter(h = 0.03)) +
# geom_line(data = predict_log, aes(x = tu_score , y = pred), col = 'red') +
# ylab("Probability")
Final Logistic Regression Model
model_4_explicit <- glm(is_popular ~ loudness + explicit + danceability + energy + no_of_artists,
family = "binomial",
data = train_log_mod)
summary(model_4_explicit)
tidy(model_4_explicit)
train_model_4_explicit <- train_log_mod %>%
add_predictions(model_4_explicit, type = "response")
roc_obj_mod4 <- train_model_4_explicit %>%
roc(response = is_popular, predictor = pred)
roc_curve <- ggroc(
data = list(
mod4 = roc_obj_mod4
),
legacy.axes = TRUE) +
coord_fixed() +
theme_classic()
auc(roc_obj_mod4)
LS0tCnRpdGxlOiAiU3BvdGlmeSBBbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQooZG9lcyBnZW5yZSBoYXZlIGFuIGltcGFjdApydW4gbW9kZWwgb24gYmVmb3JlIG9yIGFmdGVyIGFkZGluZyBnZW5yZQpjb21wYXJlIGJlZm9yZSBhbmQgYWZ0ZXIgb24gdGhlIHNhbWUgZGF0YSkKY29uc2lkZXJhdGlvbnMgYW5kIGxpbWl0YXRpb25zIC0gZ2VhcmVkIHRvd2FyZHMgeW91bmdlciBwZW9wbGUKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoc3BvdGlmeXIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG1vZGVscikKbGlicmFyeShpbmZlcikKbGlicmFyeShtb2RlbHIpCmxpYnJhcnkoZ2dmb3J0aWZ5KQpsaWJyYXJ5KEdHYWxseSkKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpzcG90aWZ5X2RhdGFfY2xlYW5fam9pbiA8LSByZWFkX2NzdigiY2xlYW5fZGF0YS9zcG90aWZ5X2NsZWFuX2pvaW4uY3N2IikKc3BvdGlmeV9kYXRhIDwtIHJlYWRfY3N2KCJyYXdfZGF0YS9zcG90aWZ5X2RhdGEuY3N2IikKYGBgCgoKIyMjIFF1ZXN0aW9uCgpXaGF0IChhdWRpbyBmZWF0dXJlcykgbWFrZXMgYSBzb25nIHBvcHVsYXIsIGFuZCBoYXMgdGhhdCBjaGFuZ2VkIG92ZXIgdGltZT8KCiMjIyBJbnRybwoKSSBwbGFuIHRvIGFuc3dlciB0aGUgcXVlc3Rpb24sIHdoYXQgbWFrZXMgYSBzb25nIG9uIHNwb3RpZnkgInBvcHVsYXIiIGFuZCBob3cgZG9lcyB0aGF0IGNoYW5nZSBvdmVyIHRpbWUuIAoKRm9yIHRoaXMgcHJvamVjdCBJIGhhdmUgdXNlZCBhIGNvbWJpbmF0aW9uIG9mIFNwb3RpZnkgZGF0YXNldHMgYXZhaWxhYmxlIG9uIEthZ2dsZSwgdGFrZW4gZnJvbSB0aGUgU3BvdGlmeSBXZWIgQVBJLiBUaGUgb3JpZ2luYWwgZGF0YXNldCBjb250YWlucyBqdXN0IHVuZGVyIDE3MCwwMDAgcm93cyB3aXRoIDE5IGNvbHVtbnMuIEkgaGF2ZSB0aGVuIGpvaW5lZCB0aGlzIHdpdGggYW5vdGhlciBkYXRhc2V0IHdoaWNoIGdhdmUgbWUgaW5mb3JtYXRpb24gb24gImdlbnJlcyIgYW5kICJmb2xsb3dlcnMiLiAoYW5kIHRpbWUgc2lnbmF0dXJlKSBFYWNoIHJvdyBpbiB0aGUgZGF0YXNldCByZXByZXNlbnRzIDEgc29uZywgaW5mb3JtYXRpb24gYWJvdXQgdGhhdCBzb25nIGFuZCBtYW55IG9mIGl0J3MgYXVkaW8gZmVhdHVyZXMuCgpJIGhhdmUgdXNlZCBSU3R1ZGlvIGZvciB0aGlzIHByb2plY3QgYXMgSSBmb3VuZCBpdCBleGNlbGxlbnQgZm9yIG1vZGVsIGJ1aWxkaW5nLgoKSSBoYWQgbm8gaXNzdWVzIHN1cnJvdW5kaW5nIHRoZSBldGhpY3Mgb2YgdXNpbmcgb3IgcHJlc2VudGluZyB0aGlzIGRhdGEuIEkgaGFkIHRvIGdldCBhdXRoZW50aWNhdGlvbiB0byB1c2UgdGhlIFNwb3RpZnkgd2ViIGFwaSBidXQgaXQgaXMgcmVhZGlseSBhdmFpbGFibGUgZm9yIHBlb3BsZSB0byB2aWV3IGFuZCBhbmFseXNlLgoKIyMjIFRoZSBWYXJpYWJsZXMKCkJhc2ljIEluZm8KYXJ0aXN0cyA8Y2hyPiAtIHRoZSBhcnRpc3Qgb3IgYXJ0aXN0cyB3aG8gYXBwZWFycyBvbiB0aGUgdHJhY2sKdHJhY2tfbmFtZSA8Y2hyPiAtIG5hbWUgb2YgdGhlIHNvbmcKdHJhY2tfaWQgPGNocj4gLSBhIGRpc3RpbmN0IGlkIHRvIHJlcHJlc2VudCB0aGUgc29uZwp5ZWFyIDxkYXRlPiAtIHllYXIgdGhlIHRyYWNrIHdhcyByZWxlYXNlZApkdXJhdGlvbl9zZWMgPGRibD4gLSBkdXJhdGlvbiBvZiB0aGUgdHJhY2sgaW4gc2Vjb25kcwprZXkgPGZjdHI+IC0gdGhlIGtleSBvZiB0aGUgc29uZyAgMC0xMQptb2RlIDxmY3RyPiAtIG1ham9yIG9yIG1pbm9yIGtleQp0aW1lX3NpZ25hdHVyZSA8ZmN0cj4gLSB0aW1lIHNpZ25hdHVyZSBvZiB0aGUgc29uZwp0ZW1wbyA8ZGJsPiAtIG92ZXJhbGwgdGVtcG8gb2YgdGhlIHRyYWNrIGluIEJQTQpleHBsaWNpdCA8ZmN0PiAtIGRvZXMgdGhlIHRyYWNrIGNvbnRhaW4gZXhwbGljaXQgY29udGVudAoKZGVjYWRlIDxkYXRlPiAtIGRlY2FkZSBvZiByZWxlYXNlCm5vX29mX2FydGlzdHMgPGRibD4gLSB0aGUgbnVtYmVyIG9mIGFydGlzdHMgYXBwZWFyaW5nIG9uIGVhY2ggdHJhY2sKZm9sbG93ZXJzIC0gCmdlbnJlIC0gCmlzX3BvcHVsYXIgPGxnbD4gLSBpcyB0aGUgcG9wdWxhcml0eSByYXRpbmcgNTAgb3Igb3ZlcgoKCkFsbCBvbiBhIHNjYWxlIG9mIDAgLSAxMDAKIC0gYWNvdXN0aWNuZXNzIDxkYmw+IC0gYSBtZWFzdXJlIG9mIGhvdyBhY291c3RpYyB0aGUgdHJhY2sgaXMgKHdhcyBpdCByZWNvcmRlZCBpbiBhIGxpdmUgc2V0dGluZyBvciBzdHVkaW8pCgogLSBkYW5jZWFiaWxpdHkgPGRibD4gLSBob3cgc3VpdGFibGUgaXMgdGhlIHRyYWNrIGZvciBkYW5jaW5nLCBiYXNlZCBvbiByaHl0aG0gc3RhYmlsaXR5LCB0ZW1wbyBhbmQgYmVhdCBzdHJlbmd0aC4KCi0gZW5lcmd5IC0gbWVhc3VyZXMgdGhlIGludGVuc2l0eSBhbmQgYWN0aXZpdHkgbGV2ZWwKCi0gaW5zdHJ1bWVudGFsbmVzcyAtIG1lYXN1cmVzIGhvdyBtdWNoIHZvY2FscyB0aGVyZSBhcmUgaW4gYSB0cmFjay4gVGhlIGhpZ2hlciB0aGUgbnVtYmVyLCB0aGUgbGVzcyB2b2NhbHMgaW4gdGhlIHRyYWNrCgotIGxpdmVuZXNzIC0gZGV0ZWN0cyB0aGUgcHJlc2VuY2Ugb2YgYW4gYXVkaWVuY2UgaW4gdGhlIHJlY29yZGluZy4gVGhlIGhpZ2hlciB0aGUgbGl2ZW5lc3MgdGhlIGhpZ2hlciB0aGUgcHJvYmFiaWxpdHkgaXQgd2FzIHJlY29yZGVkIGxpdmUuCgotIGxvdWRuZXNzIC0gdGhlIG92ZXJhbGwgbG91ZG5lc3Mgb2YgYSB0cmFjay4gT3JpZ2luYWxseSBpbiBkYiwgc2NhbGVkIHRvIG1hdGNoIHRoZSBvdGhlciBhdWRpbyBmZWF0dXJlcy4KCi0gc3BlZWNoaW5lc3MgLSBtZWFzdXJlcyB0aGUgcHJlc2VuY2Ugb2Ygc3Bva2VuIHdvcmQgaW4gYSB0cmFjay4gVGhlIGNsb3NlciB0byAxMDAsIHRoZSBtb3JlIGV4Y2x1c2l2ZWx5IHNwZWVjaC1saWtlIHRoZSByZWNvcmRpbmcuIFJhcCBoYXMgaGlnaGVyIHNjb3JlIHRoYW4gZm9say4KCi0gdmFsZW5jZSAtIHRoZSBoaWdoZXIgdGhlIHZhbHVlIHRoZSBtb3JlIHBvc2l0aXZlIGEgdHJhY2sgc291bmRzKGUuZy4gaGFwcHksIGNoZWVyZnVsKS4gVGhlIGxvd2VyIHRoZSBzY29yZSB0aGUgbW9yZSBuZWdhdGl2ZSBpdCBzb3VuZHMgKGUuZy4gc2FkLCBhbmdyeSkKCiMjIyBwb3B1bGFyaXR5IC0gIFNwb3RpZnkgLSAgIlRoZSBwb3B1bGFyaXR5IG9mIGEgdHJhY2sgaXMgYSB2YWx1ZSBiZXR3ZWVuIDAgYW5kIDEwMCwgd2l0aCAxMDAgYmVpbmcgdGhlIG1vc3QgcG9wdWxhci4gVGhlIHBvcHVsYXJpdHkgaXMgY2FsY3VsYXRlZCBieSBhbGdvcml0aG0gYW5kIGlzIGJhc2VkLCBpbiB0aGUgbW9zdCBwYXJ0LCBvbiB0aGUgdG90YWwgbnVtYmVyIG9mIHBsYXlzIHRoZSB0cmFjayBoYXMgaGFkIGFuZCBob3cgcmVjZW50IHRob3NlIHBsYXlzIGFyZS4iCgoKIyMgSHlwb3RoZXNpcyBUZXN0cyBvbiBBdWRpbyBGZWF0dXJlcwoKVHdvIHNhbXBsZSAtIGluZGVwZW5kZW50IHRlc3RzCgpJbmRlcGVuZGVudCBoZXJlIG1lYW5zIHRoYXQgdGhlcmUgaXMgbm8gcmVhc29uIHRvIGJlbGlldmUgdGhhdCBvYnNlcnZhdGlvbnMgaW4gdGhlIHR3byBzYW1wbGVzIGNhbiBiZSBwYWlyZWQgaW4gYW55IHdheS4gKGkuZS4gdGhlcmUncyBubyByZWFzb24gdG8gYmVsaWV2ZSB0aGUgZGFuY2VhYmlsaXR5IGluIHRoZSA2MHMgaXMgdGhlIHNhbWUgYXMgdGhlIDIwMTBzKQoKQnkgcmFuZG9tbHkgc2h1ZmZsaW5nIChpLmUuIHBlcm11dGluZykgdGhlIGRlY2FkZSBsYWJlbHMgd2UgbG9zZSBhbnkgcmVsYXRpb25zaGlwIHRoYXQgdGhlcmUgd2FzIGJldHdlZW4gZGVjYWRlIGFuZCBkYW5jZWFiaWxpdHkuIFRoaW5rIG9mIHRoaXMgc2h1ZmZsaW5nIGFzIGRldGFjaGluZyB0aGUgbGFiZWxzIGZyb20gcm93cyBhbmQgdGhlbiByYW5kb21seSBhc3NpZ25pbmcgdGhlbSBiYWNrIHRvIHJvd3MuIFRoZW4gd2Ugc2VlIHdoaWNoIG9mIHRoZSBmb2xsb3dpbmcgb2NjdXJzOgoKSWYgdGhlcmUgd2FzIG5vIHJlbGF0aW9uc2hpcCBpbiB0aGUgZmlyc3QgcGxhY2UgKGkuZS4gdGhleSBhcmUgaW4gZmFjdCBpbmRlcGVuZGVudCkgdGhlbiByYW5kb21seSBzaHVmZmxpbmcgdGhlbSBzaG91bGQgaGF2ZSBubyBpbXBsaWNhdGlvbi4KSWYgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBncm91cHMgaW4gb3VyIHNhbXBsZSBpcyBtdWNoIGxhcmdlciB0aGFuIHRoZSBkaWZmZXJlbmNlIG9uY2UgdGhlIGxhYmVscyBhcmUgc2h1ZmZsZWQgaXTigJlzIGJlY2F1c2UgdGhlcmUgaXMgYSByZWFsIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgZ3JvdXBzLCBhbmQgaXTigJlzIG5vdCBqdXN0IGRvd24gdG8gc2FtcGxpbmcgdmFyaWF0aW9uLgoKVGhpcyBpcyBhbiBleGFtcGxlIG9mIHRoZSBoeXBvdGhlc2lzIHRlc3RzIHdoaWNoIHdlcmUgY2FycmllZCBvdXQgb24gZWFjaCBhdWRpbyBmZWF0dXJlLgoKSDA6IFRoZSBtZWFuIGRhbmNlYWJpbGl0eSBpbiAxOTYwcyBpcyB0aGUgc2FtZSBhcyB0aGUgbWVhbiBkYW5jZWFiaWxpdHkgaW4gMjAxMHMKCkhhOiBUaGUgbWVhbiBkYW5jZWFiaWxpdHkgaW4gMTk2MHMgaXMgbGVzcyB0aGFuIHRoZSBtZWFuIGRhbmNlYWJpbGl0eSBpbiAyMDEwcwoKSDA6IFRoZSBkaWZmZXJlbmNlIGluIG1lYW5zIGluIDAKSGE6IGRhbmNlYWJpbGl0eTIwMjAgLSBkYW5jZWFiaWxpdHkxOTYwID4gMApgYGB7ciBpbmNsdWRlPUZBTFNFfQpkYW5jZV9kZWNhZGVfaHlwIDwtIHNwb3RpZnlfZGF0YV9jbGVhbl9qb2luICU+JSAKICBzZWxlY3QoZGVjYWRlLCBkYW5jZWFiaWxpdHkpICU+JSAKICBmaWx0ZXIoZGVjYWRlID09IDE5NjAgfCBkZWNhZGUgPT0gMjAxMCkgJT4lIAogIG11dGF0ZShkZWNhZGUgPSBhcy5mYWN0b3IoZGVjYWRlKSkKCm51bGxfZGlzdHJpYnV0aW9uIDwtIGRhbmNlX2RlY2FkZV9oeXAgJT4lIAogIHNwZWNpZnkoZGFuY2VhYmlsaXR5IH4gZGVjYWRlKSAlPiUgCiAgaHlwb3RoZXNpemUobnVsbCA9ICJpbmRlcGVuZGVuY2UiKSAlPiUgCiAgZ2VuZXJhdGUocmVwcyA9IDUwMDAsIHR5cGUgPSAicGVybXV0ZSIpICU+JSAKICBjYWxjdWxhdGUoc3RhdCA9ICJkaWZmIGluIG1lYW5zIiwgb3JkZXIgPSBjKCIyMDEwIiwgIjE5NjAiKSkgCgpvYnNlcnZlZF9zdGF0IDwtIGRhbmNlX2RlY2FkZV9oeXAgJT4lIAogIHNwZWNpZnkoZGFuY2VhYmlsaXR5IH4gZGVjYWRlKSAlPiUKICBjYWxjdWxhdGUoc3RhdCA9ICJkaWZmIGluIG1lYW5zIiwgb3JkZXIgPSBjKCIyMDEwIiwgIjE5NjAiKSkKCm51bGxfZGlzdHJpYnV0aW9uICU+JQogIHZpc3VhbGlzZSgpICsKICBzaGFkZV9wX3ZhbHVlKG9ic19zdGF0ID0gb2JzZXJ2ZWRfc3RhdCwgZGlyZWN0aW9uID0gInJpZ2h0IikKCnBfdmFsdWUgPC0gbnVsbF9kaXN0cmlidXRpb24gJT4lCiAgZ2V0X3BfdmFsdWUob2JzX3N0YXQgPSBvYnNlcnZlZF9zdGF0LCBkaXJlY3Rpb24gPSAicmlnaHQiKQpgYGAKCiMjIyBIb3cgZG8gdGhlIGF1ZGlvIGZlYXR1cmVzIGNoYW5nZSBvdmVyIHRpbWUKCmBgYHtyfQpzcG90aWZ5X2RhdGFfY2xlYW5fcGl2b3QgPC0gc3BvdGlmeV9kYXRhX2NsZWFuX2pvaW4gJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gYWNvdXN0aWNuZXNzOnZhbGVuY2UsCiAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiYXVkaW9fZmVhdHVyZSIsCiAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIAogIGdyb3VwX2J5KHllYXIsIGF1ZGlvX2ZlYXR1cmUpICU+JSAKICBtdXRhdGUoYXZnX2ZlYXR1cmUgPSBtZWFuKHZhbHVlKSkKYGBgCgoKUGxvdCB3aXRoIGFsbCBBdWRpbyBGZWF0dXJlcwpgYGB7cn0KYXVkaW90X2ZlYXR1cmVzX2FsbCA8LSBzcG90aWZ5X2RhdGFfY2xlYW5fcGl2b3QgJT4lCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0geWVhciwgeSA9IGF2Z19mZWF0dXJlLCBncm91cCA9IGF1ZGlvX2ZlYXR1cmUsIAogICAgICBjb2xvdXIgPSBhdWRpb19mZWF0dXJlKSArCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDIpICsKICB5bGltKDAsIDEwMCkgKwogIGxhYnMoeCA9ICJZZWFyIiwKICAgICAgIHkgPSAiVmFsdWUiLAogICAgICAgdGl0bGUgPSAiQXVkaW8gRmVhdHVyZXMgT3ZlciBUaW1lIiwKICAgICAgIHN1YnRpdGxlID0gIkF2ZyBwZXIgeWVhciIsCiAgICAgICBjb2xvdXIgPSAiQXVkaW8gRmVhdHVyZSIpICsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAgIkRhcmsyIikgKwogIHRoZW1lKGF4aXMudGV4dCAgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE1LCBmYW1pbHkgPSAiVGltZXMiKSwKICAgICAgICBheGlzLnRpdGxlICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTUsIGZhbWlseSA9ICJUaW1lcyIpLAogICAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNSwgZmFtaWx5ID0gIlRpbWVzIiksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEwLCBmYW1pbHkgPSAiVGltZXMiKQogICkgCgojZ2dzYXZlKGF1ZGlvdF9mZWF0dXJlc19hbGwsICJwbG90X2ltYWdlcy9hdWRpb19mZWF0dXJlc19hbGwucG5nIikKYGBgCgpQbG90IHdpdGggYXVkaW8gZmVhdHVyZXMgc2hvd2luZyBjaGFuZ2UKYGBge3J9CmF1ZGlvX2ZlYXR1cmVzX2N1dCA8LSBzcG90aWZ5X2RhdGFfY2xlYW5fcGl2b3QgJT4lCiAgICBmaWx0ZXIoYXVkaW9fZmVhdHVyZSA9PSAiYWNvdXN0aWNuZXNzIiB8CiAgICAgICAgICAgYXVkaW9fZmVhdHVyZSA9PSAiaW5zdHJ1bWVudGFsbmVzcyIgfAogICAgICAgICAgIGF1ZGlvX2ZlYXR1cmUgPT0gImRhbmNlYWJpbGl0eSIgfAogICAgICAgICAgIGF1ZGlvX2ZlYXR1cmUgPT0gInNwZWVjaGluZXNzIiB8CiAgICAgICAgICAgYXVkaW9fZmVhdHVyZSA9PSAibG91ZG5lc3MiKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0geWVhciwgeSA9IGF2Z19mZWF0dXJlLCBncm91cCA9IGF1ZGlvX2ZlYXR1cmUsIAogICAgICBjb2xvdXIgPSBhdWRpb19mZWF0dXJlKSArCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDIpICsKICB5bGltKDAsIDEwMCkgKwogIGxhYnMoeCA9ICJZZWFyIiwKICAgICAgIHkgPSAiVmFsdWUiLAogICAgICAgdGl0bGUgPSAiQXVkaW8gRmVhdHVyZXMgYnkgUmVsZWFzZSBZZWFyIiwKICAgICAgIHN1YnRpdGxlID0gIkF2ZyBwZXIgeWVhciIsCiAgICAgICBjb2xvdXIgPSAiQXVkaW8gRmVhdHVyZSIpICsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAgIkRhcmsyIikgKwogIHRoZW1lKGF4aXMudGV4dCAgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE4LCBmYW1pbHkgPSAiVGltZXMiKSwKICAgICAgICBheGlzLnRpdGxlICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTgsIGZhbWlseSA9ICJUaW1lcyIpLAogICAgICAgIHRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxOCwgZmFtaWx5ID0gIlRpbWVzIiksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0LCBmYW1pbHkgPSAiVGltZXMiKQogICkgCgpnZ3NhdmUoInBsb3RfaW1hZ2VzL2F1ZGlvX2ZlYXR1cmVzX2N1dC5wbmciLCBkcGkgPSA3MjAsIHdpZHRoID0gMTIsIGhlaWdodCA9IDYpCgo/Z2dzYXZlCmBgYAoKYGBge3J9CnNwb3RpZnlfZGF0YV9jbGVhbl9qb2luICU+JSAKICAjbXV0YXRlKGV4cGxpY2l0ID0gYXMubnVtZXJpYyhleHBsaWNpdCkpICU+JSAKICBncm91cF9ieSh5ZWFyKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsX2V4ID0gc3VtKGV4cGxpY2l0KSkgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9leCAvIDIwKSArCiAgZ2VvbV9saW5lKGNvbG91ciA9ICJyZWQiLCBsaW5ld2lkdGggPSAyKSArCiAgeWxpbSgwLCA1MCkgKwogIGxhYnMoeCA9ICJZZWFyIiwKICAgICAgIHkgPSAiUHJvcG9ydGlvbiIsCiAgICAgICB0aXRsZSA9ICJQcm9wb3J0aW9uIG9mIEV4cGxpY2l0IFNvbmdzIiwKICAgICAgIHN1YnRpdGxlID0gImJ5IHllYXIiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0ICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTgsIGZhbWlseSA9ICJUaW1lcyIpLAogICAgICAgIGF4aXMudGl0bGUgID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxOCwgZmFtaWx5ID0gIlRpbWVzIiksCiAgICAgICAgdGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE4LCBmYW1pbHkgPSAiVGltZXMiKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTQsIGZhbWlseSA9ICJUaW1lcyIpCiAgKSAKCmdnc2F2ZSgicGxvdF9pbWFnZXMvZXhwbGljaXQucG5nIiwgZHBpID0gNzIwLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA2KQpgYGAKYGBge3J9CnNwb3Rfc2FtcGxlICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBkYW5jZWFiaWxpdHksIHkgPSBwb3B1bGFyaXR5LCBjb2xvdXIgPSBleHBsaWNpdCkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikKYGBgCgpgYGB7cn0Kc3BvdF9zYW1wbGUgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IGRhbmNlYWJpbGl0eSwgeSA9IHBvcHVsYXJpdHkpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjMURCOTU0IiwgYWxwaGEgPSAwLjgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvdXIgPSAicHVycGxlMyIsIGxpbmV3aWR0aCA9IDIpICsKICBsYWJzKHggPSAiRGFuY2VhYmlsaXR5IiwKICAgICAgIHkgPSAiUG9wdWxhcml0eSIpICsKICAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgdGhlbWUoYXhpcy50ZXh0ICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTgsIGZhbWlseSA9ICJUaW1lcyIpLAogICAgICAgIGF4aXMudGl0bGUgID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAyMCwgZmFtaWx5ID0gIlRpbWVzIiksCiAgICAgICAgdGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE4LCBmYW1pbHkgPSAiVGltZXMiKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTQsIGZhbWlseSA9ICJUaW1lcyIpCiAgKQoKI2dnc2F2ZSgicGxvdF9pbWFnZXMvcG9wX3ZzX2RhbmNlLnBuZyIsIGRwaSA9IDcyMCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKCmBgYAoKYGBge3J9CnNwb3Rfc2FtcGxlICU+JSAKICBnZ3Bsb3QoKSArCiAgYWVzKHggPSBsb3VkbmVzcywgeSA9IHBvcHVsYXJpdHkpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjMURCOTU0IiwgYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvdXIgPSAicHVycGxlMyIsIGxpbmV3aWR0aCA9IDIpICsKICBsYWJzKHggPSAiTG91ZG5lc3MiLAogICAgICAgeSA9ICJQb3B1bGFyaXR5IikgKwogICAgICAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShheGlzLnRleHQgID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxOCwgZmFtaWx5ID0gIlRpbWVzIiksCiAgICAgICAgYXhpcy50aXRsZSAgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDIyLCBmYW1pbHkgPSAiVGltZXMiKSwKICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTgsIGZhbWlseSA9ICJUaW1lcyIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCwgZmFtaWx5ID0gIlRpbWVzIikKICApCgpnZ3NhdmUoInBsb3RfaW1hZ2VzL3BvcF92c19sb3VkLnBuZyIsIGRwaSA9IDcyMCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKCmBgYAoKIyMjIEludHJvIFRvIExpbmVhciBSZWdyZXNzaW9uCgpUbyBoZWxwIG1lIGFuc3dlciBteSBxdWVzdGlvbiBvZiB3aGF0IG1ha2VzIGEgc29uZyAicG9wdWxhciIgb24gc3BvdGlmeSwgSSBkZWNpZGVkIHRvIGJ1aWxkIGFuIGV4cGxhbmF0b3J5IGxpbmVhciByZWdyZXNzaW9uIG1vZGVsLiAKClRoaXMgdHlwZSBvZiBhbmFseXNpcyBpcyB1c2VkIHRvIGRldGVybWluZSB0aGUgc3RyZW5ndGggb2YgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgcmVzcG9uc2UgdmFyaWFibGUgYW5kIG11bHRpcGxlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcy4KClNvIGluIHRoaXMgY2FzZSBJIHdpbGwgYmUgY2hvb3NpbmcgZnJvbSBhbGwgb2YgdGhlIHZhcmlhYmxlcyBJIGhhdmUganVzdCBkaXNjdXNzZWQgdG8gZXhwbGFpbiB0aGUgcG9wdWxhcml0eSBvZiBhIHNvbmcgb24gc3BvdGlmeS4KCnkgPSBiMCArIGIxeDEgKyBiMngyICsgYjN4My4uLi5ibnhuCgpwb3B1bGFyaXR5ID0gYjAgKyBiMXgxICsgYjJ4MiArIGIzeDMuLi4uYm54bgoKVG8gc3RhcnQgdGhpcyBwcm9jZXNzIEkgcGxvdCBwb3B1bGFyaXR5IGFnYWluc3QgZWFjaCBvbmUgb2YgbXkgdmFyaWFibGVzIG9yIHBvc3NpYmxlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBhbmQgZmluZCB0aGUgc3Ryb25nZXN0IGNvcnJlbGF0aW9uLgoKYGBge3J9Cm5fZGF0YSA8LSBucm93KHNwb3RpZnlfZGF0YV9mb3JfbW9kZWxsaW5nKQoKc2FtcGxlX2luZGV4IDwtIHNhbXBsZSgxOm5fZGF0YSwgc2l6ZSA9IG5fZGF0YSowLjEpCgpzcG90X3NhbXBsZSA8LSBzbGljZShzcG90aWZ5X2RhdGFfZm9yX21vZGVsbGluZywgc2FtcGxlX2luZGV4KQoKc3BvdF9zYW1wbGUgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IHllYXIsIHkgPSBwb3B1bGFyaXR5KSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNywgY29sb3VyID0gIiMxREI5NTQiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3VyID0gInB1cnBsZTIiKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHggPSAiWWVhciIsCiAgICAgICB5ID0gIlBvcHVsYXJpdHkiKSArCiAgdGhlbWUoYXhpcy50ZXh0ICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTgsIGZhbWlseSA9ICJUaW1lcyIpLAogICAgICAgIGF4aXMudGl0bGUgID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxOCwgZmFtaWx5ID0gIlRpbWVzIiksCiAgICAgICAgdGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE4LCBmYW1pbHkgPSAiVGltZXMiKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTQsIGZhbWlseSA9ICJUaW1lcyIpCiAgKQoKI2dnc2F2ZSgicGxvdF9pbWFnZXMvcG9wX3ZzX2RhbmNlLnBuZyIsIGRwaSA9IDcyMCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKYGBgCgpgYGB7cn0Kc3BvdF9zYW1wbGUgJT4lIAogIGdncGxvdCgpICsKICBhZXMoeCA9IGV4cGxpY2l0LCB5ID0gcG9wdWxhcml0eSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjcsIGNvbG91ciA9ICJyZWQ0IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpCmBgYAoKCk15IHN0cm9uZ2VzdCBjb3JyZWxhdGlvbiB3YXMgeWVhciAodGhlIHllYXIgdGhlIHRyYWNrIHdhcyByZWxlYXNlZCkgd2l0aCBhIGNvcnJlbGF0aW9uIG9mIDAuNzQuIEkgdGhlbiBhZGQgdGhpcyB0byBteSBtb2RlbCBhcyBteSBmaXJzdCBleHBsYW5hdG9yeSB2YXJpYWJsZS4KCmBgYHtyfQptb2RlbF8xYSA8LSBsbShwb3B1bGFyaXR5IH4geWVhciwKICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluX2xtKQoKc3VtbWFyeShtb2RlbF8xYSkKYGBgCgpBZnRlciBydW5uaW5nIG15IG1vZGVsIEknbSBsb29raW5nIGF0IDMgZmFjdG9yczoKIC0gVGhlIFAtdmFsdWUgLSBpcyB0aGlzIHZhcmlhYmxlIG1ha2luZyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UuIElmIHRoZSBQLXZhbHVlIGlzIGJlbG93IHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgMC4wNSB0aGVuIHdlIGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBhbmQgY29uY2x1ZGUgdGhhdCBjaGFuZ2VzIGluIHRoZSAKIAogLSBUaGUgUl4yIC0gaXMgYSBtZWFzdXJlIHRoYXQgaW5kaWNhdGVzIGhvdyBtdWNoIG9mIHRoZSB2YXJpYXRpb24gb2YgcG9wdWxhcml0eSBpcyBleHBsYWluZWQgYnkgdGhlIHllYXIKIC0gVGhlIGFkanVzdGVkIFJeMiAtIGNvbXBlbnNhdGVzIGZvciB0aGUgYWRkaXRpb24gb2YgdmFyaWFibGVzLiBTbyBhcyB3ZSdyZSBidWlsZGluZyBhbiBleHBsYW5hdG9yeSBtb2RlbCwgd2UgZG9uJ3Qgd2FudCB0aGlzIHRvIGRyb3AgbXVjaCBsb3dlciB0aGFuIHRoZSByXjIuCgpgYGB7cn0KbW9kZWxfM2EgPC0gbG0ocG9wdWxhcml0eSB+IHllYXIgKyBkYW5jZWFiaWxpdHkgKyBsb3VkbmVzcywKICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluX2xtKQoKc3VtbWFyeShtb2RlbF8zYSkKYGBgCgpgYGB7cn0KbW9kZWxfM2IgPC0gbG0ocG9wdWxhcml0eSB+IHllYXIgKyBkYW5jZWFiaWxpdHkgKyBpbnN0cnVtZW50YWxuZXNzLAogICAgICAgICAgICAgICBkYXRhID0gdHJhaW5fbG0pCgpzdW1tYXJ5KG1vZGVsXzNiKQpgYGAKCmBgYHtyfQphbm92YShtb2RlbF8zYSwgbW9kZWxfMmMpCmBgYAoKRmluYWwgTW9kZWwKCmBgYHtyfQptb2RlbF82YSA8LSBsbShwb3B1bGFyaXR5IH4geWVhciArIGRhbmNlYWJpbGl0eSArIGxvdWRuZXNzICsgbGl2ZW5lc3MgKyBleHBsaWNpdCwKICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluX2xtKQoKc3VtbWFyeShtb2RlbF82YSkKYGBgIAoKU28gaGVyZSB3ZSBoYXZlIG91ciBmaW5hbCBtb2RlbC4gSSBzdG9wcGVkIGFkZGluZyB2YXJpYWJsZXMgYXMgdGhlIEFkanVzdGVkIHJeMiBzdGFydGVkIGRyb3BwaW5nIGFuZCBvdXIgbXVsdGlwbGUgcl4yIHdhcyBiYXJlbHkgZ29pbmcgdXAuCgpTbyB3ZSBjYW4gc2VlIHRoYXQgdGhlIG1vcmUgcmVjZW50IHRoZSByZWxlYXNlLCB0aGUgbW9yZSBkYW5jZWFiaWxpdHksIHRoZSBsb3VkZXIgaXQgaXMsIHRoZSBsZXNzIGxpdmVuZXNzIGl0IGhhcy4gU28geW91IGRvbid0IHdhbnQgYSBsaXZlIHJlY29yZGluZywgeW91IHdhbnQgYSBzdHVkaW8gcmVjb3JkaW5nIHdpdGggc29tZSBleHBsaWNpdCBseXJpY3MgY2h1Y2tlZCBpbiB0aGVyZSBhcyB3ZWxsLgoKQWxsIG9mIG91ciBQLVZhbHVlcyBhcmUgc2lnbmlmaWNhbnQgYW5kIHdlIGhhdmUgYSBNdWx0aXBsZSByXjIgb2YgMC41NSwgd2l0aCBhbiBhZGp1c3RlZCByXjIgYWxzbyBvZiAwLjU1LiBUaGlzIG1lYW5zIHRoYXQgNTUlIG9mIHRoZSB2YXJpYW5jZSBpbiBwb3B1bGFyaXR5IGlzIGV4cGxhaW5lZCBvdXIgb3RoZXIgdmFyaWFibGVzLiBXaGljaCAgYWxzbyBtZWFucyB0aGF0IDQ1JSBvZiB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIGRhdGEgY2Fubm90IGJlIGV4cGxhaW5lZCBieSB0aGlzIG1vZGVsLgoKNTUlIGlzbid0IGEgdmVyeSBoaWdoIHByb3BvcnRpb24gYnV0IGl0J3Mgbm90IHRlcnJpYmxlLiBXZSBhcmUgdHJ5aW5nIHRvIG1lYXN1cmUgdGhlIHBvcHVsYXJpdHkgb2YgYSBzb25nLiBJdCdzIG5vdCBxdWl0ZSBhcyBvYnZpb3VzIGFzIGlmIHdlIHdlcmUgdHJ5aW5nIHRvIGV4cGxhaW4gdGhlIHZhbHVlIG9mIGEgaG91c2UuIFdlIG1pZ2h0IGZpbmQgdGhhdCB0aGUgcG9zdGNvZGUgYW5kIHRoZSBudW1iZXIgb2Ygcm9vbXMgZ29lcyBhIGxvbmcgd2F5IHRvIGV4cGxhaW5pbmcgdGhhdCB2YWx1ZS4gSSB0aGluayBleHBsYWluaW5nIHRoZSBwb3B1bGFyaXR5IG9mIGEgc29uZyBpcyBiaXQgbW9yZSBjb21wbGljYXRlZCB0aGFuIHRoYXQuIElmIGl0IHdhcyBlYXN5IHRvIGtub3cgd2hhdCBtYWRlIGEgc29uZyBwb3B1bGFyIHRoZW4gd2UnZCBhbGwgYmUgbXVzaWNpYW5zLgoKTWVudGlvbiBodW1hbiBiZWhhdmlvdXIsIG1lbnRpb24gdGhlIGJhc2ljIHByYWN0aWNlIG9mIHN0YXRpc3RpY3Mgd291bGQgY2FsbCB0aGlzIGEgbW9kZXJhdGUgZWZmZWN0IHNpemUuIAoKCmBgYHtyfQptb2RlbF82YiA8LSBsbShwb3B1bGFyaXR5IH4geWVhciArIGRhbmNlYWJpbGl0eSArIGxvdWRuZXNzICsgbGl2ZW5lc3MgKyBleHBsaWNpdCwKICAgICAgICAgICAgICAgZGF0YSA9IHRlc3RfbG0pCgpzdW1tYXJ5KG1vZGVsXzZiKQoKYGBgIAoKU28gbXkgbW9kZWwgaXNuJ3QgZ3JlYXQuIFdoYXQgY2FuIEkgZG8gdG8gaW1wcm92ZSB0aGlzPyBXZWxsLi4uCgpXaGVuIEkgd2FzIHJlc2VhcmNoaW5nIGhvdyBzcG90aWZ5IGNhbGN1bGF0ZSB0aGVpciBwb3B1bGFyaXR5IHNjb3JlIEkga2VwdCBjb21pbmcgYWNyb3NzIHRoaXMgb25lIHBocmFzZS4KCiMjIyA1MCBpcyB0aGUgbWFnaWMgbnVtYmVyCgpUaGUgaGlnaGVyIHlvdXIgcG9wdWxhcml0eSBpbmRleCwgdGhlIG1vcmUgbGlrZWx5IHRoZSBhbGdvcml0aG0gaXMgdG8gcmVjb21tZW5kIHlvdSB0byBuZXcgbGlzdGVuZXJzLCBhbmQgcGxhY2UgeW91IGluIGFsZ29yaXRobWljIHBsYXlsaXN0cyBsaWtlIFJlbGVhc2UgUmFkYXIgYW5kIERpc2NvdmVyIFdlZWtseS4gTWFueSB3ZWJzaXRlcyBhbmQgYmxvZ3MgaGFkIHRoZW9yaWVzIG9uIHdoYXQgbnVtYmVyIHlvdSBoYWQgdG8gaGl0IHRvIGJlIGFkZGVkIHRvIGNlcnRhaW4gZWRpdG9yaWFsIHBsYXlsaXN0cy4gCgpESVlNdXNpY2lhbiBzdWdnZXN0cyB0aGF0IGFuZCBwb3B1bGFyaXR5IG9mIDIwKyBpbiB0aGUgZmlyc3QgZmV3IHdlZWtzIG9mIHJlbGVhc2Ugd2lsbCBnZXQgeW91IG9udG8gdGhlIFJlbGVhc2UgUmFkYXIgcGxheWxpc3QgYW5kIGEgcG9wdWxhcml0eSBzY29yZSBvZiAzMCsgd2lsbCBnZXQgeW91IG9udG8gRGlzY292ZXIgV2Vla2x5LiBMb3VkbGFiIHN1Z2dlc3RlZCB0aGF0IDUwIGlzIHRoZSBtYWdpYyBudW1iZXIuIEkgbGlrZWQgdGhpcyBpZGVhIG9mIGhhdmluZyBhIHRocmVzaG9sZCBvZiB3aGV0aGVyIG9yIG5vdCBhIHNvbmcgaXMgcG9wdWxhci4gU28gZ29pbmcgYmFjayB0byBteSB2YXJpYWJsZXMgSSBjcmVhdGVkIGEgY29sdW1uIGNhbGxlZCBpc19wb3B1bGFyIHdoaWNoIGlzIG9ubHkgVFJVRSBpZiB0aGUgcG9wdWxhcml0eSBvZiB0aGUgc29uZyBpcyA1MCBvciBvdmVyLiBUaGlzIGFsc28gbGVuZHMgaXRzZWxmIG5pY2VseSB0byBhIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwuIAoKTG9naXN0aWMgcmVncmVzc2lvbiBpcyBhIHN0YXRpc3RpY2FsIGFuYWx5c2lzIG1ldGhvZCB0byBwcmVkaWN0LCBvciBleHBsYWluIGEgYmluYXJ5IG91dGNvbWUsIHN1Y2ggYXMgeWVzIG9yIG5vLCBiYXNlZCBvbiBwcmlvciBvYnNlcnZhdGlvbnMgb2YgYSBkYXRhIHNldC4KClNvIHJhdGhlciB0aGFuIHVzaW5nIHRoZSBwb3B1bGFyaXR5IHNjb3JlIEkgaGF2ZSB1c2VkIHRoZSB2YXJpYWJsZSBJIGNyZWF0ZWQgY2FsbGVkIGlzX3BvcHVsYXIsIHdoaWNoIHNwbGl0cyB0aGUgZGF0YSBpbiB0byBhIGxvZ2ljYWwgdHlwZSwgc28gaXQncyBUUlVFIGlmIHRoZSBzb25nIGlzIDUwIG9yIGFib3ZlLgoKVGhlIHdheSB0aGlzIGlzIGJ1aWxkIGlzIHZlcnkgc2ltaWxhciB0byB0aGUgbGluZWFyIG1vZGVsLiBJIGxvb2sgZm9yIGNvcnJlbGF0aW9ucywgYW5kIEkgYWRkIHRoZW0gdG8gbXkgbW9kZWwgMSBhdCBhIHRpbWUuIFRoZSBtYWluIGRpZmZlcmVuY2UgaXMgdGhhdCBJJ20gbG9va2luZyBmb3IgZm9yIGEgaGlnaCBBVUMgc2NvcmUgdGhpcyB0aW1lLCByYXRoZXIgdGhhbiB0aGUgbXVsdGlwbGUgcl5zcXVhcmVkIEkgd2FzIGxvb2tpbmcgZm9yIGluIHRoZSBsaW5lYXIgbW9kZWwuCgpJJ2xsIGV4cGxhaW4gdGhlIEFVQyBpbiBhIHNlY29uZC4gSSBkZWNpZGVkIGZvciB0aGlzIG1vZGVsIHRvIG1ha2UgYSBjb3VwbGUgb2YgY2hhbmdlcy4gSSBkZWNpZGVkIHRvIG5vIGxvbmdlciBpbmNsdWRlIHRoZSB5ZWFyIG9yIGRlY2FkZSB0aGUgc29uZyB3YXMgcmVsZWFzZWQuIElmIEknbSBzdGF5aW5nIHRydWUgdG8gbXkgb3JpZ2luYWwgcXVlc3Rpb24gdGhlbiBob3cgY291bGQgSSBwb3NzaWJseSB3cml0ZSBhIHNvbmcgdGhhdCB3YXMgcmVsZWFzZWQgaW4gdGhlIHBhc3QuIEl0IGhhZCBzdWNoIGEgbGFyZ2UgaW5mbHVlbmNlIG9uIHRoZSBsaW5lYXIgbW9kZWwgSSB0aG91Z2h0IGl0IHdvdWxkIGJlIG1vcmUgaW50ZXJlc3RpbmcgdG8gc2VlIGhvdyB0aGUgbG9naXN0aWMgbW9kZWwgZmFyZWQgd2l0aG91dCBpdC4gQW5kIHRoZW4gSSBjYW4gdGVzdCBteSBtb2RlbCBhZ2FpbnN0IGRpZmZlcmVudCBkZWNhZGVzIHRvIHNlZSBob3cgaXQgcGVyZm9ybXMuIAoKIAoKT3NjYXIgV2lsZGUgaXMgZmFtb3VzbHkgY3JlZGl0ZWQgd2l0aCBoYXZpbmcgd3JpdHRlbjog4oCcUG9wdWxhcml0eSBpcyB0aGUgb25lIGluc3VsdCBJIGhhdmUgbmV2ZXIgc3VmZmVyZWQu4oCdCgpgYGB7cn0Kc3BvdF9zYW1wbGUgJT4lIAogIG11dGF0ZShleHBsaWNpdCA9IGFzLmxvZ2ljYWwoZXhwbGljaXQpKSAlPiUgCiAgZ2dwbG90KCkgKwogIGFlcyh4ID0gbG91ZG5lc3MsIHkgPSBwb3B1bGFyaXR5LCBjb2xvdXIgPSBleHBsaWNpdCkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArCiAgbGFicyh4ID0gIkxvdWRuZXNzIiwKICAgICAgIHkgPSAiUG9wdWxhcml0eSIsCiAgICAgICB0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBQb3B1bGFyaXR5IGFuZCBMb3VuZGVzcyIsCiAgICAgICBzdWJ0aXRsZSA9ICJHcm91cGVkIGJ5IGV4cGxpY2l0IG9yIG5vdCIpICsKICAgIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICAiRGFyazIiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0ICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTUsIGZhbWlseSA9ICJUaW1lcyIpLAogICAgICAgIGF4aXMudGl0bGUgID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNSwgZmFtaWx5ID0gIlRpbWVzIiksCiAgICAgICAgdGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE1LCBmYW1pbHkgPSAiVGltZXMiKSwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTAsIGZhbWlseSA9ICJUaW1lcyIpCiAgKSAKYGBgCgoKYGBge3J9CnNwb3Rfc2FtcGxlICU+JSAKICBtdXRhdGUoZXhwbGljaXQgPSBhcy5sb2dpY2FsKGV4cGxpY2l0KSkgJT4lCmdncGxvdCgpICsKICBhZXMoeCA9IGxvdWRuZXNzLCB5ID0gYXMuaW50ZWdlcihpc19wb3B1bGFyKSwgY29sb3VyID0gZXhwbGljaXQpICsKICBnZW9tX2ppdHRlcihzaGFwZSA9IDEsCiAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIoaCA9IDAuMDUsIHcgPSAwLjA1KSwKICAgICAgICAgICAgICBhbHBoYSA9IDAuOCkgKwogICBnZW9tX2xpbmUoZGF0YSA9IHRyYWluX21vZGVsXzFfbG91ZCwgYWVzKHggPSBsb3VkbmVzcyAsIHkgPSBwcmVkKSwgY29sID0gJ3JlZCcpICsKICB5bGFiKCJQcm9iYWJpbGl0eSIpICsKICAgICAgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gICJEYXJrMiIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQgID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNSwgZmFtaWx5ID0gIlRpbWVzIiksCiAgICAgICAgYXhpcy50aXRsZSAgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE1LCBmYW1pbHkgPSAiVGltZXMiKSwKICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTUsIGZhbWlseSA9ICJUaW1lcyIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMCwgZmFtaWx5ID0gIlRpbWVzIikKICApIAoKCiMgZ2dwbG90KG1vcnRnYWdlX2RhdGEpICsKIyAgIGdlb21faml0dGVyKGFlcyh4ID0gdHVfc2NvcmUsIHkgPSBhcy5pbnRlZ2VyKGFjY2VwdGVkKSksIHNoYXBlID0gMSwgCiMgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcihoID0gMC4wMykpICsgCiMgICAgZ2VvbV9saW5lKGRhdGEgPSBwcmVkaWN0X2xvZywgYWVzKHggPSB0dV9zY29yZSAsIHkgPSBwcmVkKSwgY29sID0gJ3JlZCcpICsgCiMgICB5bGFiKCJQcm9iYWJpbGl0eSIpCmBgYAoKCkZpbmFsIExvZ2lzdGljIFJlZ3Jlc3Npb24gTW9kZWwKYGBge3J9Cm1vZGVsXzRfZXhwbGljaXQgPC0gZ2xtKGlzX3BvcHVsYXIgfiBsb3VkbmVzcyArIGV4cGxpY2l0ICsgZGFuY2VhYmlsaXR5ICsgZW5lcmd5ICsgbm9fb2ZfYXJ0aXN0cywKICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsCiAgICAgICAgICAgICBkYXRhID0gdHJhaW5fbG9nX21vZCkKCnN1bW1hcnkobW9kZWxfNF9leHBsaWNpdCkKCnRpZHkobW9kZWxfNF9leHBsaWNpdCkKCnRyYWluX21vZGVsXzRfZXhwbGljaXQgPC0gdHJhaW5fbG9nX21vZCAlPiUKICBhZGRfcHJlZGljdGlvbnMobW9kZWxfNF9leHBsaWNpdCwgdHlwZSA9ICJyZXNwb25zZSIpCgpyb2Nfb2JqX21vZDQgPC0gdHJhaW5fbW9kZWxfNF9leHBsaWNpdCAlPiUKICByb2MocmVzcG9uc2UgPSBpc19wb3B1bGFyLCBwcmVkaWN0b3IgPSBwcmVkKQoKcm9jX2N1cnZlIDwtIGdncm9jKAogIGRhdGEgPSBsaXN0KAogICAgbW9kNCA9IHJvY19vYmpfbW9kNAogICksIAogIGxlZ2FjeS5heGVzID0gVFJVRSkgKwogIGNvb3JkX2ZpeGVkKCkgKyAKICB0aGVtZV9jbGFzc2ljKCkKCmF1Yyhyb2Nfb2JqX21vZDQpCmBgYA==